#include "protocol.h"
#include "crc.h"
#include <string.h>

// 初始化解析器
void parser_init(ProtocolParser *parser) {
    parser->state = STATE_WAIT_HEADER;
    parser->data_index = 0;
}

// 处理单个字节（返回true表示解析到完整帧）
bool parser_process_byte(ProtocolParser *parser, uint8_t byte) {
    switch (parser->state) {
        case STATE_WAIT_HEADER:
            if (byte == 0xA5 || byte == 0xA6) {
                parser->frame.head = byte;
                parser->state = STATE_READ_TYPE;
            }
            break;

        case STATE_READ_TYPE:
            parser->frame.type = byte;
            parser->state = STATE_READ_LEN_HIGH;
            break;

        case STATE_READ_LEN_HIGH:
            parser->frame.len = byte << 8;
            parser->state = STATE_READ_LEN_LOW;
            break;

        case STATE_READ_LEN_LOW:
            parser->frame.len |= byte;
            parser->expected_len = parser->frame.len;
            parser->data_index = 0;
            parser->state = (parser->expected_len > 0) ? STATE_READ_DATA : STATE_READ_CRC_HIGH;
            break;

        case STATE_READ_DATA:
            parser->frame.data[parser->data_index++] = byte;
            if (parser->data_index >= parser->expected_len) {
                parser->state = STATE_READ_CRC_HIGH;
            }
            break;

        case STATE_READ_CRC_HIGH:
            parser->frame.crc = byte << 8;
            parser->state = STATE_READ_CRC_LOW;
            break;

        case STATE_READ_CRC_LOW:
            parser->frame.crc |= byte;
            parser->state = STATE_READ_END;
            break;

        case STATE_READ_END:
            parser->frame.end = byte;
            if (byte == 0xA3) {
                // 校验CRC
                uint16_t crc_len = sizeof(parser->frame.head) + sizeof(parser->frame.type) + 
                                  sizeof(parser->frame.len) + parser->frame.len;
                uint8_t *crc_data = malloc(crc_len);
                *crc_data = parser->frame.head;
                *(crc_data + 1) = parser->frame.type;
                *(crc_data + 2) = parser->frame.len >> 8;
                *(crc_data + 3) = parser->frame.len & 0xFF;
                *(crc_data + 4) = parser->frame.type;
                memcpy(crc_data+4, parser->frame.data, parser->frame.len);
                uint16_t calc_crc = rtu_crc(crc_data, crc_len);
                free(crc_data);
                if (calc_crc == parser->frame.crc) {
                    parser->state = STATE_WAIT_HEADER;
                    return true;  // 成功解析一帧
                }
            }
            // 校验失败，重置状态机
            parser_init(parser);
            break;
    }
    return false;
}

// 数据转义（A5→A5A3, A6→A6A3, A3→A3A3）
static int escape_data(const uint8_t *in, uint16_t in_len, uint8_t *out) {
    int out_len = 0;
    for (int i = 0; i < in_len; i++) {
        uint8_t byte = in[i];
        if (byte == 0xA5 || byte == 0xA6 || byte == 0xA3) {
            out[out_len++] = byte;
            out[out_len++] = 0xA3;
        } else {
            out[out_len++] = byte;
        }
    }
    return out_len;
}

// 封装协议帧（含转义和CRC）
int protocol_encode(uint8_t head, uint8_t type, const uint8_t *data, uint16_t len, uint8_t *out_buf) {
    ProtocolFrame frame;
    frame.head = head;
    frame.type = type;
    frame.len = len;
    if(len > 0){
        memcpy(frame.data, data, len);
    }
    
    frame.end = 0xA3;

    // 计算CRC
    uint16_t crc_len = sizeof(frame.head) + sizeof(frame.type) + sizeof(frame.len) + len;
    uint8_t *crc_data = malloc(crc_len);
    *(crc_data+0) = head;
    *(crc_data+1) = type;
    *(crc_data+2) = len >> 8;
    *(crc_data+3) = len & 0xFF;
    if(len > 0){
        memcpy((crc_data+4), data, len);
    }
    frame.crc = rtu_crc((uint8_t*)crc_data, crc_len);
    free(crc_data);
    // 转义数据区
    uint8_t escaped_data[256];
    int escaped_len = 0;
    
    if(len > 0)
    {
        escaped_len = escape_data(frame.data, len, escaped_data);
    }
    // 拼接最终帧
    int pos = 0;
    out_buf[pos++] = frame.head;
    out_buf[pos++] = frame.type;
    out_buf[pos++] = (uint8_t)(frame.len >> 8);
    out_buf[pos++] = (uint8_t)(frame.len & 0xFF);
    if(len > 0)
    {
        memcpy(out_buf + pos, escaped_data, escaped_len);
        pos += escaped_len;
    }
    out_buf[pos++] = (uint8_t)(frame.crc >> 8);
    out_buf[pos++] = (uint8_t)(frame.crc & 0xFF);
    out_buf[pos++] = frame.end;

    return pos; // 返回帧总长度
}
